#include "fxcc/core/graph/common/ShaderLoader.h"
#include "fxcc/core/graph/common/EffectsLoader.h"

std::unordered_map<std::string, std::shared_ptr<fxcc::graph::opengl3::Effect3d>> ShaderLoader::m_Effects;

fxcc::graph::common::EffectToken ShaderLoader::m_DefaultToken;

bool ShaderLoader::LoadFile(const fxcc::File& file)
{

	switch (file.m_FileType)
	{
	//case fxcc::FileType::_Frag_:
		//return LoadFragShader(file).get();
	case fxcc::FileType::_Effects_:
		return LoadEffects(file);
	default:
		return false;
	}
}

std::shared_ptr<fxcc::graph::opengl3::Effect3d> ShaderLoader::LoadFragShader(const fxcc::File& file)
{
	return LoadFragShaderPath(file.m_RelativePath);
}

std::shared_ptr<fxcc::graph::opengl3::Effect3d> ShaderLoader::GetEffectFormKey(const std::string& key)
{
	auto it = m_Effects.find(key);
	if (it != m_Effects.end())
	{
		return  it->second;
	}
	return 0;
}

bool ShaderLoader::Influence(fxcc::graph::common::MaterialView& material, const std::string& key)
{
	auto effect = GetEffectFormKey(key);
	if (!effect)
	{
		return false;
	}
	material.m_Params = {};
	material.m_Textures = {};
	effect->Influence(material);
	return true;
}

bool ShaderLoader::LoadEffects(const fxcc::File& file, bool force_reload)
{
	std::string path = file.m_RelativePath;
	
	EffectsLoader effectLoader;
	auto effectsDesc = effectLoader.LoadPath(file.m_RelativePath, force_reload);

	if (effectsDesc)
	{
		for (const fxcc::graph::common::EffectDesc& effectDesc : effectsDesc->m_Descs)
		{
			LoadEffect(effectDesc);
		}
	}
	return true;
}

std::shared_ptr<fxcc::graph::opengl3::Effect3d> ShaderLoader::LoadEffect(const fxcc::graph::common::EffectDesc& desc)
{
	ztclog::info("load effect %s", desc.m_Name.c_str());
	auto key = desc.m_Name;
	auto it = m_Effects.find(key);

	auto effect = std::make_shared<fxcc::graph::opengl3::Effect3d>(desc);
	m_Effects[key] = effect;
	return effect;
}

std::shared_ptr<fxcc::graph::opengl3::Effect3d> ShaderLoader::LoadFragShaderPath(const std::string& path)
{
	ztclog::info("Load shader file %s", path.c_str());

	auto it = m_Effects.find(path);
	if (it != m_Effects.end())
	{
		return it->second;
	}
	std::string fragCode = fxcc::FileUtil::ReadFileToString(path);
	
	auto effect = std::make_shared<fxcc::graph::opengl3::Effect3d>(fragCode);
	m_Effects[path] = effect;
	return effect;
}
